/**
 * 支持可输入、可下拉
 * 下拉要求code-name形式，选中时，输出ID，未选中，输出输入的文本
 */
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'dva';
import { LoadingOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { Input, Tooltip } from 'antd';
import debounce from 'lodash/debounce';
import { FormItemLayout, NoLableLayout } from '../../form/formPub.js';
import { AutoCompleteC } from '../../form';
const { Option } = AutoCompleteC;
// 给原有的DataSource添加label属性，值为原来的title
function transformOptions(dataSource) {
  return dataSource?.map((item) => {
    item.label = item.title;
    return item;
  });
}
class SearchAndSelectC extends React.PureComponent {
  onSearchStatus = false; // 标记当前是否是查询状态
  flag = true; // “虚拟文本”标记

  // 默认值
  static defaultProps = {
    title: '标的代码',
    initialValue: undefined,
    placeholder: '请输入代码或简称进行搜索',
    allowClear: true, // 允许清空
    helper: '',
    onChange: () => {},
    onRef: () => {}, // 本组件的引用
    dataIndex: ['product'],
    loading: false,
    width: '100%',
    titleDisplay: true, // 默认展示title
    codeType: '', // 类型
  };

  constructor(props) {
    super(props);
    this.state = {
      dataSource: [], // AutoComplete数据源，根据查询条件不同，从后台获取
      loading: false, // 当向后台请求数据时，loading为true
    };

    // 绑定lodash的防抖函数，避免频繁搜索的情况
    this.handleSearch = debounce(this.handleSearch, 500);
  }

  componentDidMount() {
    // 父组件对本组件的引用
    this.props.onRef(this);
    let { initialValue } = this.props;
    this.getSecuritiesList('', false, true);

    // 如果有初始化值，且初始化需要查询，则根据初始化的code进行查询，将查询结果作为列表初始化数据源
    if (initialValue) {
      this.getSecuritiesList(initialValue, false, true);
    }
  }

  // 非初始化状态下更改下拉选项(供父组件调用)
  setSelect = (value) => {
    // 设置form值
    const valueF = {};
    valueF[this.props.dataIndex] = value;
    this.props.form.setFieldsValue(valueF);

    // 根据code进行查询，将查询结果作为列表数据源
    if (value) {
      this.getSecuritiesList(value, true, true);
    }
  };

  UNSAFE_componentWillReceiveProps(nextProps) {
    // 处理当重置时，清空tooltip
    let value = nextProps.form.getFieldValue(nextProps.dataIndex);
    if (!value) {
      this.setState({
        tooltipInfo: '',
      });
    }

    // 处理异步初始化场景
    const init = this.props.initialValue;
    const initN = nextProps.initialValue;
    if (JSON.stringify(init) !== JSON.stringify(initN)) {
      // 异步场景下，若初始化值有变更，且允许查询，则执行查询回填
      if (initN) {
        this.getSecuritiesList(initN, true, true);
      } else {
        this.setSelect(null);
      }
    }
  }

  // 向后台请求接口（handleChange，标记是否需要抛出onChange事件 ）
  getSecuritiesList = (value, handleChange = false, setTooltip = true) => {
    // 查询之前，先清空原数据
    this.setState({
      dataSource: undefined,
      loading: true,
      tooltipInfo: '',
    });

    // 查询参数
    let payload = {
      type: this.props.codeType,
      currentPage: 1,
      numInPage: 10,
    };
    if (value) {
      payload.value = value;
    }
    this.props.dispatch({
      type: 'SearchAndSelectM/getSelectData',
      payload: payload,
      callback: (e) => {
        // 初始化默认加载100条数据，放在initData中管理
        if (value == '' && this.initData == undefined) {
          this.initData = e;
        }
        this.setState(
          {
            dataSource: e,
            loading: false,
          },
          () => {
            // 处理初始化时抛出onChange事件
            if (handleChange && e && e.length > 0) {
              this.props.onChange(this.props.dataIndex[0], e[0].id);
            }

            // 因初始化数据时，是代码自动选中的，并未触发handleSelect操作，顾此处也用代码添加上tooltip
            if (setTooltip && value && e && e.length > 0) {
              this.setState({
                tooltipInfo: e[0].title,
              });
            }
          },
        );
      },
    });
  };

  // 执行查询
  handleSearch = (value) => {
    // 为什么使用延时器？因为选词结束的时候search会比compositionend先一步触发，此时flag还未调整为true，故用setTimeout将其优先级滞后。
    setTimeout(() => {
      if (this.flag) {
        // 当搜索条件为空时，清空数据源
        if (!value) {
          this.setState({
            dataSource: this.initData,
          });
        } else {
          this.onSearchStatus = true;
          this.getSecuritiesList(value, false, false);
        }
      }
    }, 0);
  };

  // 执行选中
  handleSelect = (value) => {
    this.onSearchStatus = false;
    let findInDS = (this.state.dataSource || []).filter((item) => item.value === value);
    if (findInDS.length > 0) {
      // 对外抛出事件
      this.props.onChange(this.props.dataIndex[0], findInDS[0].id);
      // 更改tooltip显示内容
      this.setState({
        tooltipInfo: findInDS[0].title,
      });
    } else {
      this.props.onChange(this.props.dataIndex[0], value);
    }
  };

  // 选中 option，或 input 的 value 变化时，调用此函数
  // 这里主要处理allowClear设置为true时，点击clear按钮触发的change事件
  handleChange = (value) => {
    if (!value) {
      // 触发选项切换事件
      this.props.onChange(null);
      // 更改tooltip显示内容
      this.setState({
        tooltipInfo: '',
      });
    }
  };

  // 焦点离开事件
  onBlur = (e) => {
    /* 对于查询了信息，却未选中查询结果中的信息而焦点离开了，采用的策略是：抛出输入框内容。*/
    if (this.onSearchStatus && e.target.value.trim() !== '') {
      // 触发选项切换事件
      this.props.onChange(this.props.dataIndex[1], e.target.value);
      // 更改tooltip显示内容
      this.setState({
        tooltipInfo: e.target.value,
      });
    }
  };

  render() {
    const { styleRow, form, dataIndex, initialValue, placeholder, style, disabled, helper, allowClear, extraLayout, rules, width, title, titleDisplay } = this.props;
    const { loading } = this.state;
    const { getFieldDecorator } = form;
    let layout = extraLayout ? extraLayout : FormItemLayout;
    if (titleDisplay === false) {
      layout = NoLableLayout;
    }

    return (
      <Form.Item
        style={style}
        {...layout}
        label={
          helper ? (
            <span>
              {title}&nbsp;
              <Tooltip title={helper}>
                <QuestionCircleOutlined />
              </Tooltip>
            </span>
          ) : (
            <span>{title}</span>
          )
        }
      >
        <Tooltip placement='left' title={this.state.tooltipInfo}>
          {getFieldDecorator(dataIndex, {
            initialValue: initialValue,
            rules: rules ? rules : [],
          })(
            <AutoCompleteC
              flag={this.flag}
              style={styleRow ? styleRow : { width: width }}
              options={transformOptions(this.state.dataSource)}
              onSearch={this.handleSearch}
              onSelect={this.handleSelect}
              onChange={this.handleChange}
              placeholder={placeholder}
              allowClear={allowClear}
              dropdownClassName={this.theme}
              disabled={disabled}
            >
              <Input
                onCompositionStart={() => {
                  this.flag = false;
                }} // 处理“虚拟文本”
                onCompositionEnd={() => {
                  this.flag = true;
                }} // 处理“虚拟文本”
                onBlur={this.onBlur}
                suffix={<LoadingOutlined style={{ fontSize: loading ? 12 : 0, color: '#999' }} />}
              />
            </AutoCompleteC>,
          )}{' '}
        </Tooltip>
      </Form.Item>
    );
  }
}

// props默认值
SearchAndSelectC.propsTypes = {
  form: PropTypes.object, // form对象
  title: PropTypes.string, // 显示名称
  dataIndex: PropTypes.array, // Form识别的Item ID
  initialValue: PropTypes.object, // 初始值（传code）
  helper: PropTypes.oneOfType([
    // 提示帮助信息
    PropTypes.string,
    PropTypes.element,
  ]),
  placeholder: PropTypes.string, // 占位符
  onChange: PropTypes.func, // 选项变更事件
  allowClear: PropTypes.boolean, // 设置允许清空输入内容
  dataSource: PropTypes.array, // 通过搜索条件，从后台获取的符合查询条件的数据源
  onRef: PropTypes.func, // 本组件的引用（可用来父组件调用内部方法）
  rules: PropTypes.array, // 校验规则
  extraLayout: PropTypes.object, // {labelCol:{},wrapperCol:{}}
  disabled: PropTypes.boolean, // 是否禁用
  style: PropTypes.object, // 样式
  titleDisplay: PropTypes.boolean, // 是否展示title
};

export default connect(({ SearchAndSelectM }) => ({ SearchAndSelectM }))(SearchAndSelectC);
